{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# fractional design engine demo (polar coordinates)\n",
    "\n",
    "*<<< check out other demo models [here](https://github.com/FullControlXYZ/fullcontrol/tree/master/models/README.md) >>>*\n",
    "  \n",
    "press ctrl+F9 to run all cells in this notebook, or press shift+enter to run each cell sequentially \n",
    "\n",
    "if you change one of the code cells, make sure you run it and all subsequent cells again (in order)\n",
    "\n",
    "*this document is a jupyter notebook - if they're new to you, check out how they work: [link](https://www.google.com/search?q=ipynb+tutorial), [link](https://jupyter.org/try-jupyter/retro/notebooks/?path=notebooks/Intro.ipynb), [link](https://colab.research.google.com/)*\n### be patient :)\n\nthe next code cell may take a while because running it causes several things to happen:\n- connect to a google colab server -> download the fullcontrol code -> install the fullcontrol code\n\ncheck out [other tutorials](https://github.com/FullControlXYZ/fullcontrol/blob/master/tutorials/README.md) to understand the python code for the FullControl design"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if 'google.colab' in str(get_ipython()):\n  !pip install git+https://github.com/FullControlXYZ/fullcontrol --quiet\nimport fullcontrol as fc\nfrom google.colab import files\n",
    "from math import tau"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# printer/gcode parameters\n",
    "\n",
    "design_name = 'polar_design'\n",
    "nozzle_temp = 210\n",
    "bed_temp = 40\n",
    "print_speed = 1000\n",
    "fan_percent = 100\n",
    "printer_name='prusa_i3' # generic / ultimaker2plus / prusa_i3 / ender_3 / cr_10 / bambulab_x1 / toolchanger_T0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# design parameters\n",
    "\n",
    "radius = 20\n",
    "# Nominal Radius (mm) - This radius is achieved when fractional radius is set to 1\n",
    "# default value: 20\n",
    "\n",
    "angle_fractions = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]\n",
    "# Angle Fraction List (0-1) - List of fractional 'polar angles' for all points (angle increases anti-clockwise around a circle... 0 = positive x direction from centre, 0.25 = positive y direction, 1 is equivalent to 0) - google '2D polar angle' if unsure'\n",
    "# default value: [0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1]\n",
    "\n",
    "radial_fractions = [1, 0.5, 1, 0.5, 1, 0.5, 1, 0.5, 1, 0.5, 1]\n",
    "# Radii Fraction List (0-1) - List of fractional radii for all points (0 = centre of circle, 1 = nominal radius)\n",
    "# default value: [1,0.5,1,0.5,1,0.5,1,0.5,1,0.5,1]\n",
    "\n",
    "# Try a double-star (change all 0.5 radii to -0.5) or a coarse spiral (radii = [0.9, 0.91, 0.92, 0.93, 0.94, 0.95, 0.96, 0.97, 0.98, 0.99, 1])\n",
    "\n",
    "layers = 1\n",
    "# Layers - Number of layers to print - each layer is offset in Z by the extrusion height. Make sure layers finish at the same point they start\n",
    "# default value: 1\n",
    "\n",
    "centre_x, centre_y = 50, 50\n",
    "# XY centre - Centre of part in X and Y\n",
    "# default value: 50\n",
    "\n",
    "EW = 0.6\n",
    "# Extrusion Width (mm) - Width of printed lines - recommended value: 1.5x nozzle diameter\n",
    "# default value: 0.6\n",
    "\n",
    "EH = 0.2\n",
    "# Extrusion Height (mm) - Height of printed lines (i.e. layer thickness) - recommended value: 0.5x nozzle diameter\n",
    "# default value: 0.2\n",
    "\n",
    "travel_moves = [0]*len(angle_fractions)\n",
    "# Travel Instructions - A list of 0s and 1s (one for each point in the radii/angle lists) indicate whether to print to each point or travel to it. E.g. [0,0,0,0,0,0,0,0,0,0,1] prints all lines except the last one for the default model'\n",
    "# default value: [0]*len(angle_fractions)\n",
    "\n",
    "use_retraction = False\n",
    "# Use Retraction? - Set as True to use retraction commands (G10 and G11) before and after non-printing travel movements\n",
    "# default value: False\n",
    "\n",
    "initial_z = 0.8*EH # squash"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# generate the design (make sure you've run the above cells before running this cell)\n",
    "\n",
    "if len(angle_fractions) != len(radial_fractions) or len(angle_fractions) != len(travel_moves):\n",
    "    raise Exception(f'the number of angles ({len(angle_fractions)}) / radii ({len(radial_fractions)}) / travel_moves-IDs ({len(travel_moves)}) in angle_fractions / radial_fractions / travel_moves must be the same')\n",
    "\n",
    "def travel_retract(existing_travel_state: int, new_travel_state: int, use_retraction: bool) -> list:\n",
    "    if new_travel_state == existing_travel_state:\n",
    "        return []\n",
    "    elif new_travel_state == 0:\n",
    "        return [fc.Extruder(on=True),  fc.PrinterCommand(id='unretract')] if use_retraction else [fc.Extruder(on=True)]\n",
    "    elif new_travel_state == 1:\n",
    "        return [fc.Extruder(on=False),  fc.PrinterCommand(id='retract')] if use_retraction else [fc.Extruder(on=False)]\n",
    "    else:\n",
    "        raise Exception(f'list of \"travel_moves\" must only include values of 0 or 1. current value: {new_travel_state}')\n",
    "\n",
    "centre = fc.Point(x=centre_x, y=centre_y, z=initial_z)\n",
    "\n",
    "steps = []\n",
    "existing_travel_state = 0\n",
    "for layer in range(int(layers)):\n",
    "    for i in range(len(angle_fractions)):\n",
    "        steps.extend(travel_retract(existing_travel_state, travel_moves[i], use_retraction))\n",
    "        steps.append(fc.polar_to_point(centre, radius*radial_fractions[i], tau*angle_fractions[i]))\n",
    "        existing_travel_state = travel_moves[i]\n",
    "    centre.z += EH\n",
    "\n",
    "if fc.distance(steps[0], steps[-1]) > 0.001:\n",
    "    steps.insert(1, fc.PlotAnnotation(label='start'))\n",
    "    steps.append(fc.PlotAnnotation(label='end'))\n",
    "else:\n",
    "    steps.append(fc.PlotAnnotation(label='start/end'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# preview the design\n",
    "\n",
    "# fc.transform(steps, 'plot', fc.PlotControls(style='line'))\n",
    "# hover the cursor over the lines in the plot to check xyz positions of the points in the design\n",
    "\n",
    "# uncomment the next line to create a plot with real heights/widths for extruded lines to preview the real 3D printed geometry\n",
    "fc.transform(steps, 'plot', fc.PlotControls(color_type='print_sequence', style='tube', initialization_data={'extrusion_width': EW, 'extrusion_height': EH}))\n",
    "\n",
    "# uncomment the next line to create a neat preview (click the top-left button in the plot for a .png file) - post and tag @FullControlXYZ :)\n",
    "# fc.transform(steps, 'plot', fc.PlotControls(neat_for_publishing=True, zoom=0.9,  initialization_data={'extrusion_width': EW, 'extrusion_height': EH}))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# generate and save gcode\n",
    "\n",
    "gcode_controls = fc.GcodeControls(\n",
    "    printer_name=printer_name,\n",
    "\n",
    "    initialization_data={\n",
    "        'primer': 'front_lines_then_y',\n",
    "        'print_speed': print_speed,\n",
    "        'nozzle_temp': nozzle_temp,\n",
    "        'bed_temp': bed_temp,\n",
    "        'fan_percent': fan_percent,\n",
    "        'extrusion_width': EW,\n",
    "        'extrusion_height': EH})\n",
    "gcode = fc.transform(steps, 'gcode', gcode_controls)\nopen(f'{design_name}.gcode', 'w').write(gcode)\nfiles.download(f'{design_name}.gcode')\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### please tell us what you're doing with FullControl!\n",
    "\n",
    "- tag FullControlXYZ on social media ([twitter](https://twitter.com/FullControlXYZ), [instagram](https://www.instagram.com/fullcontrolxyz/), [linkedin](https://www.linkedin.com/in/andrew-gleadall-068587119/), [tiktok](https://www.tiktok.com/@fullcontrolxyz))\n",
    "- email [info@fullcontrol.xyz](mailto:info@fullcontrol.xyz)\n",
    "- post on the [subreddit](https://reddit.com/r/fullcontrol)\n",
    "- post in the [github discussions or issues tabs](https://github.com/FullControlXYZ/fullcontrol/issues)\n",
    "\n",
    "in publications, please cite the original FullControl paper and the github repo for the new python version:\n",
    "\n",
    "- Gleadall, A. (2021). FullControl GCode Designer: open-source software for unconstrained design in additive manufacturing. Additive Manufacturing, 46, 102109. \n",
    "- Gleadall, A. and Leas, D. (2023). FullControl [electronic resource: python source code]. available at: https://github.com/FullControlXYZ/fullcontrol"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  },
  "vscode": {
   "interpreter": {
    "hash": "2b13a99eb0d91dd901c683fa32c6210ac0c6779bab056ce7c570b3b366dfe237"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
